package com.easipass.framework.eirframeworkwebapp.controller;

import com.easipass.framework.eirframeworkcoredsl.graph.Graph;
import com.easipass.framework.eirframeworkcoredsl.graph.Link;
import com.easipass.framework.eirframeworkcoredsl.graph.Node;
import com.easipass.framework.eirframeworkjdbc.AppRepository;
import com.easipass.framework.eirframeworkjdbc.AppType;
import com.easipass.framework.eirframeworkjdbc.ServiceRepository;
import com.easipass.framework.eirframeworkjdbc.model.App;
import com.easipass.framework.eirframeworkjdbc.model.Service;
import com.easipass.framework.eirframeworkwebapp.QueryParams;
import com.google.gson.Gson;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RestController
public class Controller {

    @Autowired
    AppRepository appRepository;

    @Autowired
    ServiceRepository serviceRepository;

    @RequestMapping("/app/add/interface")
    public String addAppInterface(@RequestBody QueryParams queryParams) {
        Map<String, Object> param = queryParams.getParam();
        App app = new App();
        app.setName(MapUtils.getString(param, "name"));
        app.setType(AppType.INTERFACE.toString());
        app.setUri(MapUtils.getString(param, "url"));
        app.setCode(MapUtils.getString(param, "code"));
        app.setDescribeInfo(MapUtils.getString(param, "describe"));
        app.setLabel(MapUtils.getString(param, "label"));
        return appRepository.save(app).toString();
    }

    @RequestMapping("/app/add/script")
    public String addAppScript(@RequestBody QueryParams queryParams) {
        Map<String, Object> param = queryParams.getParam();
        App app = new App();
        app.setType(AppType.SCRIPT.toString());
        app.setName(MapUtils.getString(param, "name"));
        app.setDescribeInfo(MapUtils.getString(param, "describe"));
        app.setCode(MapUtils.getString(param, "code"));
        app.setLabel(MapUtils.getString(param, "label"));
        return appRepository.save(app).toString();
    }

    @RequestMapping("/app/add/source")
    public String addAppSource(@RequestBody QueryParams queryParams) {
        Map<String, Object> param = queryParams.getParam();
        App app = new App();
        app.setType(AppType.SOURCE.toString());
        app.setName(MapUtils.getString(param, "name"));
        app.setDescribeInfo(MapUtils.getString(param, "describe"));
        app.setCode(MapUtils.getString(param, "code"));
        app.setLabel(MapUtils.getString(param, "label"));
        app.setListeningType(MapUtils.getString(param, "listeningType"));
        return appRepository.save(app).toString();
    }

    @RequestMapping("/app/add/sink")
    public String addAppSink(@RequestBody QueryParams queryParams) {
        Map<String, Object> param = queryParams.getParam();
        App app = new App();
        app.setType(AppType.SINK.toString());
        app.setName(MapUtils.getString(param, "name"));
        app.setDescribeInfo(MapUtils.getString(param, "describe"));
        app.setCode(MapUtils.getString(param, "code"));
        app.setLabel(MapUtils.getString(param, "label"));
        app.setListeningType(MapUtils.getString(param, "listeningType"));
        return appRepository.save(app).toString();
    }

    @RequestMapping("/app/get/all/{name}")
    public String getAllByName(@PathVariable String name) {
        if (StringUtils.isBlank(name)) {
            return new Gson().toJson(appRepository.findAll());
        } else {
            return new Gson().toJson(appRepository.findAllByName(name));
        }
    }

    @RequestMapping("/app/get/all")
    public String getAll() {
        return new Gson().toJson(appRepository.findAll());
    }

    @RequestMapping("/app/get/interface/{name}")
    public String getInterfaceByName(@PathVariable String name) {
        if (StringUtils.isBlank(name)) {
            return new Gson().toJson(
                    appRepository.findAllByType(AppType.INTERFACE.toString()));
        } else {
            return new Gson().toJson(
                    appRepository.findAllByNameAndType(name, AppType.INTERFACE.toString()));
        }
    }

    @RequestMapping("/app/get/interface")
    public String getInterface() {
        return new Gson().toJson(
                appRepository.findAllByType(AppType.INTERFACE.toString()));
    }

    @RequestMapping("/app/get/script/{name}")
    public String getScriptByName(@PathVariable String name) {
        if (StringUtils.isBlank(name)) {
            return new Gson().toJson(
                    appRepository.findAllByType(AppType.SCRIPT.toString()));
        } else {
            return new Gson().toJson(
                    appRepository.findAllByNameAndType(name, AppType.SCRIPT.toString()));
        }
    }

    @RequestMapping("/app/get/script")
    public String getScript() {
        return new Gson().toJson(
                appRepository.findAllByType(AppType.SCRIPT.toString()));
    }

    @RequestMapping("/app/get/source/{name}")
    public String getSourceByName(@PathVariable String name) {
        if (StringUtils.isBlank(name)) {
            return new Gson().toJson(
                    appRepository.findAllByType(AppType.SOURCE.toString()));
        } else {
            return new Gson().toJson(
                    appRepository.findAllByNameAndType(name, AppType.SOURCE.toString()));
        }
    }

    @RequestMapping("/app/get/source")
    public String getSource() {
        return new Gson().toJson(
                appRepository.findAllByType(AppType.SOURCE.toString()));
    }

    @RequestMapping("/app/get/sink/{name}")
    public String getSinkByName(@PathVariable String name) {
        if (StringUtils.isBlank(name)) {
            return new Gson().toJson(
                    appRepository.findAllByType(AppType.SINK.toString()));
        } else {
            return new Gson().toJson(
                    appRepository.findAllByNameAndType(name, AppType.SINK.toString()));
        }
    }

    @RequestMapping("/app/get/sink")
    public String getSink() {
        return new Gson().toJson(
                appRepository.findAllByType(AppType.SINK.toString()));
    }

    @RequestMapping("/app/update")
    public String updateApp(@RequestBody Map<String,Object> param) {
        return appRepository.updateAppById(MapUtils.getString(param,"code"),
                MapUtils.getString(param,"describeInfo"),
                MapUtils.getString(param,"label"),
                MapUtils.getLong(param,"id")) > 0 ? "更新成功" : "更新失败";
    }

    @RequestMapping("/app/delete/{id}")
    public void deleteApp(@PathVariable Long id) {
        appRepository.deleteById(id);
    }

    @RequestMapping("/service/add")
    public String addServiceUserDsl(@RequestBody QueryParams queryParams) {
        Map<String, Object> param = queryParams.getParam();
        String process = MapUtils.getString(param, "process");
        String dsl = jsonToDsl(process);
        Service servoce = new Service();
        servoce.setName(MapUtils.getString(param, "name"));
        servoce.setProcess(dsl);
        servoce.setUinfo(process);
        return serviceRepository.save(servoce).toString();
    }

    @RequestMapping("/service/get/{name}")
    public String getServiceByName(@PathVariable String name) {
        if (StringUtils.isBlank(name)) {
            return new Gson().toJson(
                    serviceRepository.findAll());
        } else {
            return new Gson().toJson(
                    serviceRepository.findAllByName(name));
        }
    }

    @RequestMapping("/service/get")
    public String getService() {
        return new Gson().toJson(
                serviceRepository.findAll());
    }

    @RequestMapping("/service/update")
    public String updateService(@RequestBody  Map<String,Object> param){
        String uinfo = MapUtils.getString(param,"process");
        String process = jsonToDsl(uinfo);
        Long id = MapUtils.getLong(param,"id");
        return serviceRepository.updateServiceById(process,uinfo,id)>0?"更新成功":"更新失败";
    }

    @RequestMapping("/service/delete/{id}")
    public void deleteService(@PathVariable Long id){
        serviceRepository.deleteById(id);
    }

    private String jsonToDsl(String json) {
        List<Node> nodes = new ArrayList<>();
        List<Link> links = new ArrayList<>();
        Map<String, Object> jsonMap = new Gson().fromJson(json, HashMap.class);
        List<Map<String, Object>> nodeList = (List<Map<String, Object>>) MapUtils.getObject(jsonMap, "nodeList");
        List<Map<String, Object>> linkList = (List<Map<String, Object>>) MapUtils.getObject(jsonMap, "linkList");
        for (int i = 0; i < nodeList.size(); i++) {
            nodes.add(new Node(Integer.toString(i),
                    MapUtils.getString(nodeList.get(i), "nodeName"),
                    MapUtils.getString(nodeList.get(i), "type"),
                    MapUtils.getString(nodeList.get(i), "id")));
        }
        for (Map<String, Object> linkMap : linkList) {
            Node fromNode = findNodeByPrimaryKey(nodes, MapUtils.getString(linkMap, "sourceId"));
            Node toNode = findNodeByPrimaryKey(nodes, MapUtils.getString(linkMap, "targetId"));
            links.add(new Link(fromNode.id, toNode.id));
        }
        Graph graph = new Graph(nodes, links);
        return graph.toDSLText();
    }

    private Node findNodeByPrimaryKey(List<Node> nodes, String primaryKey) {
        for (Node node : nodes) {
            if (StringUtils.equals(primaryKey, node.primaryKey)) {
                return node;
            }
        }
        return null;
    }
}
